﻿using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using Xioa_UI.Attribute;

namespace Xioa_UI.Domain;

public static class CarryOut
{
    internal static IEnumerable<Type>? TypesTOne { get; set; }

    internal static IEnumerable<Type>? TypesTTwo { get; set; }

    static CarryOut()
    {
        // 泛型父类
        TypesTOne = GetTypes(typeof(IAlternateNesting<>));
        TypesTTwo = GetTypes(typeof(IAlternateNesting<,>));
    }

    internal static IEnumerable<Type>? GetTypes(Type t1)
    {
        var assembly = Assembly.GetEntryAssembly();
        var inter = assembly?.GetTypes();

        var subclassTypes = inter?
            .Where(t => t.IsClass && !t.IsAbstract)
            .Where(t => t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == t1))
            .ToList();

        return subclassTypes;
    }


    internal static IAlternateNesting<T>? GetValue<T>(string nestingAttributeUseDescription,
        string nestingAttributeScope)
    {
        var resType = TypesTOne?
            .FirstOrDefault(item =>
                (item.GetCustomAttribute(typeof(NestingAttribute), true)
                    as NestingAttribute)?.UseDescription == nestingAttributeUseDescription &&
                (item.GetCustomAttribute(typeof(NestingAttribute), true)
                    as NestingAttribute)?.Scope == nestingAttributeScope
            );
        // var resType = resTypes?.FirstOrDefault(item => item.GetInterfaces().Any(i =>
        //     i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IAlternateNesting<T>)));
        if (resType is not null)
            return Activator.CreateInstance(resType) as IAlternateNesting<T>;
        return null;
    }

    private static IAlternateNesting<T, TResult>? GetValue<T, TResult>(string nestingAttributeUseDescription,
        string nestingAttributeScope)
    {
        var resType = TypesTTwo?
            .FirstOrDefault(item =>
                (item.GetCustomAttribute(typeof(NestingAttribute), true)
                    as NestingAttribute)?.UseDescription == nestingAttributeUseDescription &&
                (item.GetCustomAttribute(typeof(NestingAttribute), true)
                    as NestingAttribute)?.Scope == nestingAttributeScope
            );
        // var resType = resTypes?.FirstOrDefault(item => item.GetInterfaces().Any(i =>
        //     i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IAlternateNesting<T, TResult>)));
        if (resType is not null)
            return Activator.CreateInstance(resType) as IAlternateNesting<T, TResult>;
        return null;
    }

    public static void Run<TWork>(string? nestingAttributeUseDescription, string? nestingAttributeScope)
    {
        if (string.IsNullOrWhiteSpace(nestingAttributeScope) ||
            string.IsNullOrWhiteSpace(nestingAttributeUseDescription))
            return;
        var getValue =
            GetValue<TWork>(nestingAttributeUseDescription, nestingAttributeScope);
        if (getValue is null) throw new Exception("Not Found Types !");
        getValue.DoWork();
    }

    public static void Run<TWork>(string? nestingAttributeUseDescription, string? nestingAttributeScope,
        TWork value)
    {
        if (string.IsNullOrWhiteSpace(nestingAttributeScope) ||
            string.IsNullOrWhiteSpace(nestingAttributeUseDescription))
            return;
        var getValue =
            GetValue<TWork>(nestingAttributeUseDescription, nestingAttributeScope);
        if (getValue is null) throw new Exception("Not Found Types !");
        getValue.DoWork(value);
    }

    public static TResult? Run<T, TResult>(string? nestingAttributeUseDescription, string? nestingAttributeScope, T value)
    {
        if (string.IsNullOrWhiteSpace(nestingAttributeScope) ||
            string.IsNullOrWhiteSpace(nestingAttributeUseDescription))
            return default;
        var res = GetValue<T, TResult>(nestingAttributeUseDescription, nestingAttributeScope);
        if (res is not null)
            return res.DoWorkResult(value);
        throw new Exception("Not Found Types !");
    }

    public static TResult? Run<T, TResult>(string? nestingAttributeUseDescription, string? nestingAttributeScope)
    {
        if (string.IsNullOrWhiteSpace(nestingAttributeScope) ||
            string.IsNullOrWhiteSpace(nestingAttributeUseDescription))
            return default;
        var res = GetValue<T, TResult>(nestingAttributeUseDescription, nestingAttributeScope);
        if (res is not null)
            return res.DoWorkResult();
        throw new Exception("Not Found Types !");
    }
}